package com.merry.generics;

import java.util.ArrayList;
import java.util.List;

/**
 * 通过 add方法中，我们可以看出，第二种和第三种方法写法上一个采用泛型，一个没采用泛型，但是效果都是差不多的。
 * 所以也可以证明泛型是可以擦除的。
 */
public class GenericsTest {
    public static void main(String[] args) {
        GenericsTest genericsTest = new GenericsTest();
        //常规写法
        genericsTest.add(1,1);
        //泛型写法
        genericsTest.add(1,1,1);
        //使用泛型类
        MyClass1<String,Number> class1 = new MyClass1<>();
        class1.add(1);
        class1.print("1");
    }

    /**
     * 不使用泛型，我们想要实现两个数的相加操作，只能采用下面的重载方法，这样会导致方法数量激增。
     */
    public Integer add(Integer a, Integer b){
        return a+b;
    }
    public Double add(Double a,Double b){
        return a+b;
    }
    /**
     * 或者采用另一种方法实现相加操作。
     * 我们知道所有的数字类都实现了Number方法。
     */
    public double add(Number a,Number b){
        return a.doubleValue()+b.doubleValue();
    }

    /**
     * 第三种实现方法，泛型的使用：
     * 就需要使用到泛型了，
     */
    public <T extends Number,R extends Number> double add(T a, R b, T c){
        T x;
        x = a;
        return a.doubleValue()+b.doubleValue()+c.doubleValue();
    }
}


class MyClass{
    String name;
    String password;
    Integer sum;
    Integer add(Integer i1){
        sum = sum+i1;
        return sum;
    };
}

class MyClass1<T extends String,R extends Number>{
    T name;
    T password;
    R sum;
    R add(R i1){
        Double d =sum.doubleValue()+i1.doubleValue();
        return (R) d;
    }

    /**
     * 方法中定义了泛型变量与类中的冲突了，以方法中为准，就近原则。
     */
    <R extends String> R print(R s){
        System.out.println(s);
        return s;
    }


    private <T> void test(List<? super T> dst, List<T> src){
        List<? extends Number> list = new ArrayList<>();
        for (T t : src) {
            dst.add(t);
        }
    }


    /**
     * 由于这个地方程序无法做限制，<? extends Number> 和 <? super Number>可以混用，所以我们需要在使用的时候做出严格的限制。
     * 首先泛型出现的原因只有一条：限制用户的某些行为。
     * 所以：方法参数类型中使用 extends，这样我们就限制了用户入参的父类。对于这个方法来说，我不关心list中的对象是什么类型，反正它是Number的子类，我就可以使用Number中的公共方法。
     *      如果采用 super，那么我只能确定它的子类是Number，这个范围就很大了，比如Object，所以我们无法在这个方法中使用除了Object类定义的方法之外的方法，它扩大了范围，不推荐使用。
     */
    public static void printList(List<? extends Number> list) {
        for (Number number : list) {
            System.out.println(number);
        }
    }

    /**
     * 方法定义的返回类型被限制成 CharSequence 及其父类型的列表。
     * out变量：使用 ? super Number。
     */
    List<? extends CharSequence> processStringList(List<?> list) {
        String elem1 = "789";
        List<? extends CharSequence> v = new ArrayList<>();
        System.out.println("list size:" + (list == null ? 0: list.size()));
        return v;
    }
}

